package stone926.mods.more_enchantments.items.bow;

import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.PersistentProjectileEntity;
import net.minecraft.entity.projectile.ShulkerBulletEntity;
import net.minecraft.entity.projectile.SpectralArrowEntity;
import net.minecraft.item.BowItem;
import net.minecraft.item.ItemStack;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Util;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import stone926.mods.more_enchantments.MoreEnchantmentsMod;
import stone926.mods.more_enchantments.enchantments.ShulkerBulletShooterEnchantment;
import stone926.mods.more_enchantments.interfaces.IShulkerBullet;
import stone926.mods.more_enchantments.util.RandomUtil;

import java.util.List;
import java.util.Random;
import java.util.function.Predicate;

public class ShulkerBow extends BowItem implements StoneBow {

  public ShulkerBow(Settings settings) {
    super(settings);
  }

  @Override
  public void onStoppedUsing(ItemStack bowStack, World world, LivingEntity user, int remainingUseTicks) {
    if (user instanceof PlayerEntity playerEntity) {
      boolean isCreative = playerEntity.getAbilities().creativeMode;
      ItemStack arrowStack = playerEntity.getArrowType(bowStack);
      if (!arrowStack.isEmpty() || isCreative) {
        if (arrowStack.isEmpty()) {arrowStack = new ItemStack(MoreEnchantmentsMod.MIXED_GUNPOWDER);}
        int useTime = this.getMaxUseTime(bowStack) - remainingUseTicks;
        float pullProgress = BowItem.getPullProgress(useTime);
        if (pullProgress >= 0.25D) {
          int enchLvl = EnchantmentHelper.getLevel(MoreEnchantmentsMod.SHULKER_BULLET_SHOOTER, bowStack);
          boolean isSuccess = false;
          List<LivingEntity> nearbyLivingEntities = world.getEntitiesByClass(
            LivingEntity.class,
            Box.from(user.getPos()).expand(ShulkerBulletShooterEnchantment.getEntitySearchRadius(enchLvl)),
            EntityPredicates.VALID_ENTITY
          ).stream().filter(target -> target != user).toList();
          if (!nearbyLivingEntities.isEmpty()) {
            isSuccess = true;
            for (int k = 0; k < ShulkerBulletShooterEnchantment.getShootCount(enchLvl,user.getRandom()); k++) {
              for (LivingEntity target : nearbyLivingEntities) {
                ShulkerBulletEntity bullet = new ShulkerBulletEntity(world, user, target, user
                  .getRandom()
                  .nextInt(2) == 0 ? Direction.Axis.Z : Direction.Axis.X);
                Random r = user.getRandom();
                bullet.setPosition(
                  bullet.getX() + r.nextGaussian(),
                  user.getY() + user.getHeight() + 4 + r.nextGaussian(),
                  bullet.getZ() + r.nextGaussian()
                );
                ((IShulkerBullet) bullet).setExtraBulletDamage(enchLvl / 1.2F);
                ((IShulkerBullet) bullet).setFlash(EnchantmentHelper.getLevel(MoreEnchantmentsMod.FLASH, bowStack));
                world.spawnEntity(bullet);
              }
            }
          }
          if (isSuccess) {
            int infiniteLvl = EnchantmentHelper.getLevel(MoreEnchantmentsMod.INFINITE, bowStack);
            if (infiniteLvl <= 2 && !isCreative) {
              arrowStack.decrement(1);
              if (arrowStack.isEmpty()) {playerEntity.getInventory().removeOne(arrowStack);}
            }
            if (user instanceof ServerPlayerEntity serverPlayerEntity) {
              serverPlayerEntity.sendSystemMessage(new TranslatableText("message.stone_more_enchantments.shulker_bullet_shoot", user.getDisplayName()), Util.NIL_UUID);
            }
            bowStack.damage(new Random().nextDouble() > pullProgress ? 3 : 1, playerEntity, p -> p.sendToolBreakStatus(playerEntity.getActiveHand()));
            if (new Random().nextDouble() > pullProgress) {user.damage(DamageSource.MAGIC, enchLvl * 2);}
          } else {
            if (user instanceof ServerPlayerEntity serverPlayerEntity) {
              serverPlayerEntity.sendSystemMessage(new TranslatableText("message.stone_more_enchantments.shulker_bullet_fail", user.getDisplayName()), Util.NIL_UUID);
            }
          }
        }
      }
    }
  }

  @Override
  public Predicate<ItemStack> getProjectiles() {
    return stack -> stack.isOf(MoreEnchantmentsMod.SHULKER_GUNPOWDER);
  }

  @Override
  public void mobUse(MobEntity user, LivingEntity target, ItemStack stack, float pullProgress, ItemStack usingStack) {
    int enchLvl = EnchantmentHelper.getLevel(MoreEnchantmentsMod.SHULKER_BULLET_SHOOTER, usingStack);
    World world = user.getEntityWorld();
    List<LivingEntity> nearbyLivingEntities = world
      .getEntitiesByClass(
        LivingEntity.class,
        Box.from(user.getPos()).expand(ShulkerBulletShooterEnchantment.getEntitySearchRadiusForMob(enchLvl) - 2),
        EntityPredicates.VALID_LIVING_ENTITY
      )
      .stream()
      .filter(target2 -> target2 != user)
      .filter(x -> x.isPlayer() || RandomUtil.isPossible(0.7, user.getRandom()))
      .toList();
    if (!nearbyLivingEntities.isEmpty()) {
      for (int k = 0; k < ShulkerBulletShooterEnchantment.getShootCount(enchLvl,user.getRandom()); k++) {
        for (LivingEntity target2 : nearbyLivingEntities) {
          ShulkerBulletEntity bullet = new ShulkerBulletEntity(world, user, target2, new Random().nextInt(2) == 0 ? Direction.Axis.Z : Direction.Axis.X);
          Random r = user.getRandom();
          bullet.setPosition(
            bullet.getX() + r.nextGaussian(),
            user.getY() + user.getHeight() + 4 + r.nextGaussian(),
            bullet.getZ() + r.nextGaussian()
          );
          ((IShulkerBullet) bullet).setExtraBulletDamage(enchLvl);
          ((IShulkerBullet) bullet).setFlash(EnchantmentHelper.getLevel(MoreEnchantmentsMod.FLASH, stack));
          world.spawnEntity(bullet);
        }
      }
    } else {
      PersistentProjectileEntity persistentProjectileEntity = new SpectralArrowEntity(
        user.world, user.getX(), user.getY() + user.getEyeHeight(user.getPose()), user.getZ()
      );
      double d = target.getX() - user.getX();
      double e = target.getBodyY(0.3333333333333333D) - persistentProjectileEntity.getY();
      double f = target.getZ() - user.getZ();
      double g = Math.sqrt(d * d + f * f);
      persistentProjectileEntity.setVelocity(d, e + g * 0.20000000298023224D, f, 2, 0);
      user.world.spawnEntity(persistentProjectileEntity);
    }

  }

}
